package pl.edu.pw.perg.compinfodb.ui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.BorderFactory;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTable;
import javax.swing.JTree;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellRenderer;

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.richclient.application.ApplicationWindow;
import org.springframework.richclient.application.PageComponentContext;
import org.springframework.richclient.application.support.AbstractView;
import org.springframework.richclient.application.support.DefaultViewDescriptor;
import org.springframework.richclient.command.CommandGroup;
import org.springframework.richclient.command.support.AbstractActionCommandExecutor;
import org.springframework.richclient.command.support.ShowViewCommand;
import org.springframework.richclient.progress.TreeStatusBarUpdater;
import org.springframework.richclient.tree.FocusableTreeCellRenderer;
import org.springframework.richclient.util.PopupMenuMouseListener;

import pl.edu.pw.perg.compinfodb.datamodel.ElementTableModel;
import pl.edu.pw.perg.compinfodb.datamodel.SelectableTreeNode;
import pl.edu.pw.perg.compinfodb.datamodel.StructureTreeModel;
import pl.edu.pw.perg.compinfodb.datamodel.TypeComboModel;
import pl.edu.pw.perg.compinfodb.entities.IVirtualElement;
import pl.edu.pw.perg.compinfodb.manager.IElementTypeManager;
import pl.edu.pw.perg.compinfodb.manager.IFieldManager;
import pl.edu.pw.perg.compinfodb.manager.IPhysicalElementManager;
import pl.edu.pw.perg.compinfodb.manager.IVirtualElementManager;

public class NewEquipmentManagerView extends AbstractView implements
    ApplicationListener, IEquipmentManagerView, ListSelectionListener 
    {

  private IVirtualElementManager virtualElementManager;
  private IPhysicalElementManager physicalElementManager;
  private IElementTypeManager typeManager;
  private IFieldManager fieldManager;
  private DefaultViewDescriptor dvd;
  private ShowViewCommand showView; 
  private JTree elementTree;
  private DefaultTreeModel elementTreeModel;
  private JTable table;
  private ApplicationWindow window;
  private JTable historyTable = new JTable();
  private StructureTreeModel structureTreeModel;
  private ChoseElementExecutor choseExecutor = new ChoseElementExecutor();
  // private DeleteExecutor deleteExecutor = new DeleteExecutor();
  // private final VisibleTreeNode viewRootNode = new VisibleTreeNode("Slave");
  private ElementTableModel equipmentTableModel;
  // private FilterableComboBoxListModel<ElementCategory> categoryComboModel;
//  private TypeComboModel typeComboModel;
  // private JComboBox categoryCombo;
  private JComboBox typeCombo; // = new JComboBox();
  // private NewElementAction newEltCommand = new NewElementAction();
  // private SwitchToSearchModeExecutor searchModeExecutor = new
  // SwitchToSearchModeExecutor();
  // private SearchExecutor searchExecutor = new SearchExecutor();
  // //private ColorRenderer cellRenderer = new ColorRenderer();
  // private SaveExecutor saveExecutor = new SaveExecutor();
//  private ImportCommand importCommand;
  private ColorRenderer renderer;
  
  public void setVirtualElementManager(
      IVirtualElementManager virtualElementManager) {
    this.virtualElementManager = virtualElementManager;
  }

  public void setPhysicalElementManager(
      IPhysicalElementManager physicalElementManager) {
    this.physicalElementManager = physicalElementManager;
  }

  public void setTypeManager(IElementTypeManager typeManager) {
    this.typeManager = typeManager;
  }

  public void setFieldManager(IFieldManager fieldManager) {
    this.fieldManager = fieldManager;
  }

  private JTable createElementTable() {

    return new JTable(equipmentTableModel) {
      @Override
      public void tableChanged(TableModelEvent e) {
        super.tableChanged(e);
        for (int i = 0; i < getColumnCount(); i++) {
          getColumnModel().getColumn(i).setCellRenderer(new ColorRenderer());
        }
      }
    };
  }

  private JComboBox createTypeCombo() {
    TypeComboModel typeComboModel = new TypeComboModel(typeManager);
    JComboBox typeCombo = new JComboBox(typeComboModel);
//    typeCombo.addActionListener(equipmentTableModel);
    return typeCombo;
  }

  protected void registerLocalCommandExecutors(PageComponentContext context) {
//    showView = (ShowViewCommand) dvd.createShowViewCommand(window);
    context.register("choseCommand", choseExecutor);
    
//     context.register("saveCommand", saveExecutor);
    // context.register("searchCommand", searchExecutor);
    // context.register("importCommand", importCommand);
    // context.register(GlobalCommandIds.DELETE, deleteExecutor);

  }

  @Override
  protected JComponent createControl() {
    JPanel view = new JPanel(new BorderLayout());

    createEquipmentManagerTree();
    // createSlaveTree();
    // createCategoryCombo();
    // createTypeCombo();
    // createEquipmentTable();

    JScrollPane sp1 = new JScrollPane(elementTree);
    sp1.setBorder(BorderFactory.createTitledBorder("Element Tree"));
    
    JPanel p2 = new JPanel(new BorderLayout());
    p2.setBorder(BorderFactory.createTitledBorder("Type filter"));
    typeCombo = createTypeCombo();
    p2.add(typeCombo, BorderLayout.WEST);
    typeCombo = createTypeCombo();

    table = createElementTable();
    JScrollPane sp2 = new JScrollPane(table);
    sp2.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
    sp2.setBorder(BorderFactory.createTitledBorder("Element Details"));

    JScrollPane sp3 = new JScrollPane(historyTable);
    sp3.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
    sp3.setBorder(BorderFactory.createTitledBorder("Element History"));

    JSplitPane spl2 = new JSplitPane(JSplitPane.VERTICAL_SPLIT, sp2, sp3);
    spl2.setDividerLocation(400);
    JPanel p1 = new JPanel(new BorderLayout());
    p1.add(p2, BorderLayout.NORTH);
    p1.add(spl2, BorderLayout.CENTER);

    JSplitPane spl1 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, sp1, p1);
    spl1.setDividerLocation(200);
    view.add(spl1, BorderLayout.CENTER);
    return view;
  }

  private void createEquipmentManagerTree() {
    // tworzenie korzeni
//    SelectableTreeNode rootNode = new SelectableTreeNode("CMS");
//    List<VirtualElement> elements = virtualElementManager.findRoots();
//    for (Iterator<VirtualElement> i = elements.iterator(); i.hasNext();) {
//      IVirtualElement elt = (VirtualElement) i.next();
//      SelectableTreeNode eltNode = createTree(elt);
//      rootNode.add(eltNode);
//    }

//    this.elementTreeModel = new DefaultTreeModel(rootNode);
    this.elementTree = new JTree(structureTreeModel);
    elementTree.setShowsRootHandles(true);

    // listener dla status bara
    // konfiguracja co ma byc wyswietlane na status barze
    elementTree.addTreeSelectionListener(new TreeStatusBarUpdater(
        getStatusBar()) {
      public String getSelectedObjectName() {
        IVirtualElement selectedElt = getSelectedElement(elementTree);
        
        if (selectedElt != null)
          return selectedElt.toString();

        return "CMS";
      }
    });
    // listener dla aktualizacji dostepnych komend
    elementTree.addTreeSelectionListener(new TreeSelectionListener() {
      public void valueChanged(TreeSelectionEvent e) {
        updateCommands();
        if (getSelectedElementNode(elementTree) != null)
          // chosenElementTree.clearSelection()
          ;
      }
    });
    elementTree.addTreeSelectionListener(structureTreeModel);
    // sprawdzenie, czy popup ma sie pokazac
    // tak, jesli wybrany jakis element
    elementTree.addMouseListener(new PopupMenuMouseListener() {
      protected boolean onAboutToShow(MouseEvent e) {
        return !isRootOrNothingSelected();
      }

      // tworzenie popupu
      protected JPopupMenu getPopupMenu() {
        return createElementPopupContextMenu();
      }
    });
    elementTree.addMouseListener(new MouseAdapter() {
      public void mouseClicked(MouseEvent e) {
        if (e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1
        // && choseExecutor.isEnabled()
        ) {
          // choseExecutor.execute();
        }
      }
    });

    elementTree.setCellRenderer(getTreeCellRenderer());
    elementTree.setRootVisible(true);
  }

  private JPopupMenu createElementPopupContextMenu() {
    // delete, chose, edit
    CommandGroup group = getWindowCommandManager().createCommandGroup(
        "elementViewTableCommandGroup",
        new Object[] { "choseCommand", "separator", "deleteCommand",
        // newEltCommand
        });
    return group.createPopupMenu();
  }

  private boolean isRootOrNothingSelected() {
    return elementTree.getSelectionCount() == 0
        || (elementTree.getSelectionCount() == 1 && elementTree
            .isRowSelected(0));
  }

//  private SelectableTreeNode createTree(IVirtualElement elt) {
//    SelectableTreeNode rootNode = new SelectableTreeNode(elt);
//    Collection<VirtualElement> children = elt.getChildren();
//    for (Iterator<VirtualElement> i = children.iterator(); i.hasNext();) {
//      IVirtualElement child = (IVirtualElement) i.next();
//      rootNode.add(createTree(child));
//    }
//    return rootNode;
//
//  }

  private static DefaultMutableTreeNode getSelectedElementNode(JTree tree) {
    DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree
        .getLastSelectedPathComponent();
    if (node == null || !(node.getUserObject() instanceof IVirtualElement))
      return null;
    return node;
  }

  private static IVirtualElement getSelectedElement(JTree tree) {
    DefaultMutableTreeNode node = getSelectedElementNode(tree);
    if (node != null)
      return (IVirtualElement) node.getUserObject();

    return null;
  }

  private void updateCommands() {
//    showView.setEnabled(true);
    choseExecutor.setEnabled(true);
    // deleteExecutor.setEnabled(true);
    // searchExecutor.setEnabled(true);
    // searchModeExecutor.setEnabled(true);
    // saveExecutor.setEnabled(false);
    // importCommand.setEnabled(true);
    //
    // newEltCommand.setEnabled(getSelectedElement(elementTree) != null);
    SelectableTreeNode selected = (SelectableTreeNode) getSelectedElementNode(elementTree);
    // jesli nie zaznaczono zadnego elementu lub jest on juz wybrany
    if (selected == null || selected.isSelected())
      choseExecutor.setEnabled(false);
    //
    // // if (getSelectedElementNode(chosenElementTree) == null)
    // // deleteExecutor.setEnabled(false);
    // if (!searchModeExecutor.isEnabled())
    // searchExecutor.setEnabled(false);
    // // if(equipmentTableModel.isNewSelected(table.getSelectedRows()))
    // // saveExecutor.setEnabled(true);

  }

  public void onApplicationEvent(ApplicationEvent arg0) {
    
  }

  public TreeCellRenderer getTreeCellRenderer() {

    return treeCellRenderer;
  }

  public void valueChanged(ListSelectionEvent arg0) {
    // TODO Do czego to?

  }

  private DefaultTreeCellRenderer treeCellRenderer = new FocusableTreeCellRenderer() {

    public Component getTreeCellRendererComponent(JTree tree, Object value,
        boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) {
      super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row,
          hasFocus);
      SelectableTreeNode node = (SelectableTreeNode) value;
      if (node.isRoot()) {
        this.setIcon(getIconSource().getIcon("cms.bullet"));
      } else {
        IVirtualElement o = (IVirtualElement) node.getUserObject();
        this.setText(o.toString());
        // TODO: wyszarzanie jesli bez elementow
        // if(o.)
        if (!node.isSelected()) {

          this.setIcon(getIconSource().getIcon("not_selected.bullet"));
        } else if (node.isSelected()) {
          this.setIcon(getIconSource().getIcon("selected.bullet"));
        }

      }
      return this;
    }
  };

  private class ChoseElementExecutor extends AbstractActionCommandExecutor {
    public void execute() {

      
      SelectableTreeNode selected = (SelectableTreeNode) getSelectedElementNode(elementTree);
      selected.setSelected(true);
      updateCommands();

    }
  }

  public void setEquipmentTableModel(ElementTableModel equipmentTableModel) {
    this.equipmentTableModel = equipmentTableModel;
  }

  

  public void setStructureTreeModel(StructureTreeModel structureTreeModel) {
    this.structureTreeModel = structureTreeModel;
  }
}
